#include "Renderer_PCH.h"
#include "DynGeometryMgr.h"

/*--------------------------------------------------------------------------*/

DynGeometryMgr::DynGeometryMgr() :
	m_dynamicSurface(NULL),
	m_dynGeometryBuffer(NULL),
	m_bufferOffset(NULL)
{
	m_dynGeometry_mutex			= g_Kernel->CreateNewMutex();
}

/*--------------------------------------------------------------------------*/

DynGeometryMgr::~DynGeometryMgr()
{
	delete m_dynGeometry_mutex;

	if (m_dynamicSurface)
	{
		delete m_dynamicSurface;
	}
}

/*--------------------------------------------------------------------------*/

void DynGeometryMgr::InitDynGeometryMgr()
{
	m_dynGeometryBuffer		= g_Renderer->GetRendererStorageMgr()->CreateBuffer("DynGeometryBuffer", DYNGEOMETRY_BUFFER_SIZE, true, GL_ARRAY_BUFFER);
}

/*--------------------------------------------------------------------------*/

DynamicSurface* DynGeometryMgr::BeginGeometry( uint numVertices, uint types )
{
	m_dynGeometry_mutex->Lock();

	__Check(m_dynamicSurface == NULL);
	//__Check(m_dynamicVertexArray);

	m_dynamicSurface = new DynamicSurface(numVertices, types);

	if (m_dynamicSurface->GetSize() + m_bufferOffset >= DYNGEOMETRY_BUFFER_SIZE)
	{
		m_bufferOffset = 0;
	}

	//__Info("Allocating: %d - %d", m_bufferOffset, m_dynamicSurface->GetSize());

	uchar* ptn = m_dynGeometryBuffer->Lock(m_dynamicSurface->GetSize(), m_bufferOffset);
	m_dynamicSurface->SetMemory(ptn);
	return m_dynamicSurface;
}

/*--------------------------------------------------------------------------*/

RVertexArray* DynGeometryMgr::EndGeometry()
{
	__Check(m_dynamicSurface);
	m_dynGeometryBuffer->Flush();
	
	RVertexArray* vao = new RVertexArray("DynVAO_" + std::to_string(rand()));

	if (m_dynamicSurface->vPosition0())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iPosition0);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vPosition0() - (uint)m_dynamicSurface->GetVertexData(), 
															s));
	}

	if (m_dynamicSurface->vPosition1())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iPosition1);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vPosition1() - (uint)m_dynamicSurface->GetVertexData(), 
															s));	
	}

	if (m_dynamicSurface->vNormal0())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iNormal0);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vNormal0() - (uint)m_dynamicSurface->GetVertexData(), 
															s));	
	}

	if (m_dynamicSurface->vNormal1())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iNormal1);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vNormal1() - (uint)m_dynamicSurface->GetVertexData(), 
															s));	
	}

	if (m_dynamicSurface->vTexcoord0())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iTexcoord0);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vTexcoord0() - (uint)m_dynamicSurface->GetVertexData(), 
															s));	
	}

	if (m_dynamicSurface->vTexcoord1())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iTexcoord1);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vTexcoord1() - (uint)m_dynamicSurface->GetVertexData(), 
															s));	
	}

	if (m_dynamicSurface->vColor0())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iColor0);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vColor0() - (uint)m_dynamicSurface->GetVertexData(), 
															s));	
	}

	if (m_dynamicSurface->vColor1())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iColor1);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vColor1() - (uint)m_dynamicSurface->GetVertexData(), 
															s));	
	}

	if (m_dynamicSurface->vInstancing())
	{
		const SemanticInfo* s = g_Renderer->GetSemanticInfo(ESemantic::iInstancing);
		__Check(s);
		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
															m_bufferOffset + (uint)m_dynamicSurface->vInstancing() - (uint)m_dynamicSurface->GetVertexData(), 
															s));	
// 
// 		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
// 															16 + m_bufferOffset + (uint)m_dynamicSurface->vColor1() - (uint)m_dynamicSurface->GetVertexData(), 
// 															s));	
// 
// 		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
// 															32 + m_bufferOffset + (uint)m_dynamicSurface->vColor1() - (uint)m_dynamicSurface->GetVertexData(), 
// 															s));	
// 
// 		vao->m_declarations.push_back(RVertexDeclaration(	m_dynGeometryBuffer->GetHandle(), 
// 															48 + m_bufferOffset + (uint)m_dynamicSurface->vColor1() - (uint)m_dynamicSurface->GetVertexData(), 
// 															s));
	}

	m_bufferOffset += m_dynamicSurface->GetSize();

	delete m_dynamicSurface;
	m_dynamicSurface = NULL;

	m_dynGeometry_mutex->Unlock();
	return vao;
}

/*--------------------------------------------------------------------------*/

void DynGeometryMgr::EndGeometryAndDraw( ETopology::Type topology, int begin, int end )
{
	RVertexArray* va = g_Renderer->GetDynGeometryMgr()->EndGeometry();
	va->Bind(NULL);

	GLenum glenum = GL_POINTS;

	switch(topology)
	{
	case ETopology::Lines:
		{
			glenum = GL_LINES;
			break;
		}
	case ETopology::Points:
		{
			glenum = GL_POINTS;
			break;
		}
	case ETopology::Triangles:
		{
			glenum = GL_TRIANGLES;
			break;
		}
	case ETopology::TriangleStrip:
		{
			glenum = GL_TRIANGLE_STRIP;
			break;
		}
	}

	glDrawArrays(glenum, begin, end);
	delete va;
}

/*--------------------------------------------------------------------------*/
